﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;


 
using log4net;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using System.Web;

namespace MShop.Core.Service.Search
{
	public class SearchService : ISearchService
	{
		private static readonly ILog Logger = LogManager.GetLogger(typeof (SearchService));
	
	
		private readonly ITextExtractor _textExtractor;
		

		public SearchService( ITextExtractor textExtractor)
		{			
			this._textExtractor = textExtractor;			
		}

		#region ISearchService Members

		public void UpdateContent(ISearchableContent searchContent)
		{
			using (IndexBuilder indexBuilder = CreateIndexBuilder())
			{
				indexBuilder.UpdateContent(searchContent);
			}
		}

        public void AddContent(ISearchableContent searchContent)
		{
			using (IndexBuilder indexBuilder = CreateIndexBuilder())
			{
				indexBuilder.AddContent(searchContent);
			}
		}

        public void DeleteContent(ISearchableContent searchContent)
		{
			using (IndexBuilder indexBuilder = CreateIndexBuilder())
			{
				indexBuilder.DeleteContent(searchContent);
			}
		}

        public void AddContent(IList<ISearchableContent> searchContents)
		{
			using (IndexBuilder indexBuilder = CreateIndexBuilder())
			{
                foreach (ISearchableContent searchContent in searchContents)
				{
                    indexBuilder.AddContent(searchContent);
				}
			}
		}

	

		public SearchResultCollection FindContent(string queryText, int pageIndex, int pageSize)
		{
			return this.FindContent(queryText, null, pageIndex, pageSize);
		}

		public SearchResultCollection FindContent(string queryText, IList<string> categoryNames, int pageIndex, int pageSize)
		{
			// Check queryText for invalid fields
            //if (queryText.Contains("viewroleid:"))
            //{
            //    throw new SearchException("Don't try to mess with security!");	
            //}		
		
			IndexQuery query = new IndexQuery(GetIndexDirectory());

			try
			{
				return query.Find(queryText, categoryNames, pageIndex, pageSize);
			}
			catch (ParseException ex)
			{
				Logger.Error(string.Format("Invalid query: {0}", queryText), ex);
				throw new SearchException("Invalid search query", ex);
			}
		}

		public SearchIndexProperties GetIndexProperties()
		{
			SearchIndexProperties indexProperties = new SearchIndexProperties();
			indexProperties.IndexDirectory = GetIndexDirectory();

			IndexReader indexReader = IndexReader.Open(Lucene.Net.Store.FSDirectory.GetDirectory(indexProperties.IndexDirectory),true);
			try
			{
				indexProperties.NumberOfDocuments = indexReader.NumDocs();
			}
			finally
			{
				indexReader.Close();
			}
			indexProperties.LastModified = new DateTime(IndexReader.LastModified(Lucene.Net.Store.FSDirectory.GetDirectory(indexProperties.IndexDirectory)));
			return indexProperties;
		}

		/// <summary>
		/// Rebuild the full-text index.
		/// </summary>
		/// <param name="searchableModules">A list of (legacy) searchable modules in the installation.</param>
		public void RebuildIndex(IEnumerable<MShop.Core.Service.Search.ISearchableContent> searchableModules)
		{
			
			string indexDirectory = GetIndexDirectory();

            using (IndexBuilder indexBuilder = new IndexBuilder(indexDirectory, true, this._textExtractor))
            {

                // Add legacy searchable content
                if (searchableModules != null)
                {
                    foreach (ISearchableContent searchable in searchableModules)
                    {                       
                            try
                            {
                                indexBuilder.AddContent(searchable);
                            }
                            catch (Exception ex)
                            {
                                Logger.Error(string.Format("Indexing of legacy searchContent item with path {0} failed.", searchable.ToSearchContent().Path), ex);

                            }
                       
                    }
                }
            }
		}

		#endregion

		private IndexBuilder CreateIndexBuilder()
		{
			return new IndexBuilder(GetIndexDirectory(), false, this._textExtractor);
		}

		private string GetIndexDirectory()
		{            
            return HttpContext.Current.Server.MapPath("~/Index");
		}
	}
}
